package com.sweet;

import com.sweet.entity.MessageBody;
import com.sweet.entity.TokenObj;
import com.sweet.entity.User;
import com.sweet.enums.MessageType;
import com.sweet.service.IdUtils;
import com.sweet.store.FriendsStore;
import com.sweet.store.TokenStore;
import com.sweet.store.UserStore;
import io.netty.util.internal.StringUtil;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.handler.BodyHandler;

import java.util.UUID;

/**
 * Created by sweet on 2019/1/29.
 * ---------------------------
 */
public class IMHttpServerVerticle extends AbstractVerticle {

  @Override
  public void start() throws Exception {
    super.start();
    Router router = Router.router(vertx);

    router.route().handler(BodyHandler.create())
            .failureHandler(ex -> {
              ex.failure().printStackTrace();
              ex.response().end(ResultModel.error(ex.failure().getMessage()).toJson());
            });

    router.post("/app/login").handler(this::login);
    router.post("/app/register").handler(this::register);
    router.post("/app/searchFriend")
            .handler(this::authHandler)
            .handler(this::searchFriend);
    router.post("/app/addFriend")
            .handler(this::authHandler)
            .handler(this::addFriend);

    router.post("/app/refreshToken")
            .handler(this::authHandler)
            .handler(this::refreshTokenHandler);

    vertx.createHttpServer().requestHandler(router)
            .listen(9091, server -> {
              if (server.succeeded()) {
                System.out.println("im http server start 9091");
              } else {
                server.cause().printStackTrace();
              }
            });
  }

  private void refreshTokenHandler(RoutingContext routingContext) {

  }

  private void addFriend(RoutingContext routingContext) {
    JsonObject bodyAsJson = routingContext.getBodyAsJson();
    System.out.println("addFriend: " + bodyAsJson.encode());
    TokenObj tokenObj = context.get("token");
    String uid = tokenObj.getUser().getId();
    String fid = bodyAsJson.getString("fid");
    FriendsStore.instance().addFriend(uid, fid, routingContext.vertx())
            .setHandler(r -> {
              if (r.succeeded()) {
                // todo 推送 socket 消息给另一方
                MessageBody messageBody = new MessageBody(MessageType.ADD,
                        UUID.randomUUID().toString().replaceAll("-", ""),
                        "请求添加为好友", fid, uid, "", "" + System.currentTimeMillis());
                routingContext.vertx().eventBus().send(MainVerticle.PUSH_MESSAGE_ADDRESS, messageBody.toJson());
                routingContext.response().end(ResultModel.success(new JsonObject()).toJson());
              } else {
                routingContext.response().end(ResultModel.error("添加失败").toJson());
              }
            });
  }

  private void authHandler(RoutingContext context) {
    final String token = context.getBodyAsJson().getString("token");
    if (StringUtil.isNullOrEmpty(token)) {
      context.response().end("token无效");
      return;
    }

    TokenStore.instance().findKey(token, context.vertx())
            .setHandler(f -> {
              if (f.succeeded()) {
                if (f.result() != null && !f.result().expired()) {
                  context.put("token", token);
                  context.next();
                } else {
                  context.response().end(ResultModel.authError().toJson());
                  return;
                }
              } else {
                context.response().end(ResultModel.authError().toJson());
                return;
              }
            });
  }

  private void searchFriend(RoutingContext context) {
    JsonObject bodyAsJson = context.getBodyAsJson();
    TokenObj tokenObj = context.get("token");
    String phone = bodyAsJson.getString("phone");
    UserStore.instance().search(phone, vertx)
            .setHandler(r -> {
              if (r.succeeded()) {
                FriendsStore.instance().findFriend(tokenObj.getUser().getId(), r.result())
                        .setHandler(f -> {
                          if (f.succeeded()) {
                            JsonObject userJson0 = r.result().toJson();
                            userJson0.remove("password");
                            JsonObject userJson = new JsonObject().put("user", userJson0);
                            userJson.put("friendFlag", f.result());
                            context.response().end(ResultModel.success(userJson).toJson());
                          } else {
                            context.response().end(ResultModel.error(f.cause().getMessage()).toJson());
                          }
                        });
              } else {
                context.response().end(ResultModel.error(r.cause().getMessage()).toJson());
              }
            });
  }

  private void register(RoutingContext context) {
    User user = context.getBodyAsJson().mapTo(User.class);
    final String token = UUID.randomUUID().toString().replaceAll("-", "");
    user.setId(IdUtils.get().nextId() + "");
    UserStore.instance().register(user, context.vertx())
            .compose(f -> TokenStore.instance().saveToken(token, user, context.vertx()))
            .setHandler(r -> {
              if (r.succeeded()) {
                JsonObject userJson = user.toJson();
                userJson.remove("password");
                context.response().end(ResultModel.success(new JsonObject()
                        .put("user", userJson)
                        .put("token", token)).toJson());
              } else {
                context.response().end(ResultModel.error(r.cause().getMessage()).toJson());
              }
            });
  }

  private void login(RoutingContext context) {
    JsonObject bodyAsJson = context.getBodyAsJson();
    String phone = bodyAsJson.getString("phone");
    String password = bodyAsJson.getString("password");
    System.out.println("phone: " + phone + ", password: " + password);
    final String token = UUID.randomUUID().toString().replaceAll("-", "");
    UserStore.instance().login(phone, password, context.vertx())
            .compose(f -> TokenStore.instance().saveToken(token, f, context.vertx()))
            .setHandler(r -> {
              if (r.succeeded()) {
                JsonObject jsonObject = r.result().toJson();
                jsonObject.remove("password");
                context.response().end(ResultModel.success(new JsonObject()
                        .put("user", jsonObject)
                        .put("token", token)).toJson());
              } else {
                context.response().end(ResultModel.error(r.cause().getMessage()).toJson());
              }
            });
  }
}

enum ResultType {
  success, error, auth
}

class ResultModel {
  private ResultType type;
  private JsonObject data;
  private String error;

  public static ResultModel success(JsonObject data) {
    return new ResultModel(ResultType.success, data, "");
  }

  public static ResultModel error(String error) {
    return new ResultModel(ResultType.error, new JsonObject(), error);
  }

  public static ResultModel authError() {
    return new ResultModel(ResultType.auth, new JsonObject(), "token失效");
  }

  private ResultModel(ResultType type, JsonObject data, String error) {
    this.type = type;
    this.data = data;
    this.error = error;
  }

  public String toJson() {
    return new JsonObject()
            .put("type", type)
            .put("data", data)
            .put("error", error).toString();
  }
}


